#include "renderer.h"

#include <assert.h>
#include <windows.h>		// Header File For Windows
#include <gl\gl.h>			// Header File For The OpenGL32 Library
#include <gl\glu.h>
#include <gl\glaux.h>

#include "character.h"
#include "level.h"
#include "platform.h"
#include "zomby.h"
#include "fx.h"
#include "slope.h"
#include "rect.h"
#include "hunter.h"	//? remove
#include "camera.h"
#include "circle.h"
#include "frame.h"
#include "point2.h"
#include "texture.h"
#include "animation.h"
#include "projectile.h"
#include "kolobok.h"
#include "cloud.h"
#include "respawn.h"
#include "source.h"
#include "polygon.h"
#include "bird.h"
#include "physics.h"

#include "tools.h"
#include "globals.h"
#include "game.h"

//AUX_RGBImageRec* loadBMP(char *filename)                // Loads A Bitmap Image
//{
//	return auxDIBImageLoad(filename);       // Load The Bitmap And Return A Pointer
//}

#define _OPTIMIZE_renderLevel

Renderer* Renderer::_instance = 0;

Renderer::Renderer(){
	base =0;
	font =0;
	tobj =NULL;
};

Renderer* Renderer::Instance(){

	if (_instance == 0){
	
		_instance = new Renderer;
	}
	return _instance;
}

// render extra animation (if available), in front of the main animation
//? should be possible to render behind too
void Renderer::renderExtraAnimation(Character* character){

	Rect* rect;
	Texture* sprite;
	Animation* cur_animation;

	cur_animation =character->cur_animation;
	rect =cur_animation->frames[cur_animation->cur_frame]->box;

	if(cur_animation->extra){
		Point2 center;
		character->getCenter(&center);
		if(character->orientation->x>0){
			center.x +=rect->xHi -rect->xLo;
		}
		else{
			center.x -=rect->xHi -rect->xLo;
		}

		int cur_frame =cur_animation->cur_frame;
		rect =cur_animation->extra->frames[cur_frame]->box;
		sprite =cur_animation->extra->sprites[cur_frame];
		if(sprite){
			renderRect(rect, sprite, &center, (character->orientation->x>0)^character->mirrored, character->layer);
		}
	}
}

int Renderer::select(float x, float y, int btn)
{
	const BUFSIZE =512;	//?

	GLuint selectBuf[BUFSIZE];
	GLint hits;

	// set selection buffer
	glSelectBuffer (BUFSIZE, selectBuf);
	glRenderMode (GL_SELECT);

	// initialize stack
	glInitNames();
	glPushName(0);

	// selection volume
	glPushMatrix ();
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity ();
	glOrtho (x+1, x-1, y+1, y-1, -1, 1);	//?

	// draw primitives
	glMatrixMode (GL_MODELVIEW);
	glLoadIdentity ();

	glLoadName(1);
	switch(btn)
	{
	case btnStart:
		drawStartButton();
		break;
	case btnExit:
		drawExitButton();
		break;
	}
//	draw_func();
	glPopMatrix ();
	glFlush ();

	hits = glRenderMode (GL_RENDER);

	return hits;
} 

void Renderer::drawAxis(float half_len){

	glBegin(GL_LINES);
		glColor3f(0.0, 1.0, 0.0);
        glVertex3f(-half_len, 0.0, 0.0);
        glVertex3f(half_len, 0.0, 0.0);
        glColor3f(0.0, 0.0, 1.0);
        glVertex3f(0.0, -half_len, 0.0);
        glVertex3f(0.0, half_len, 0.0);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(0.0, 0.0, -half_len);
        glVertex3f(0.0, 0.0, half_len);
	glEnd();
}

void Renderer::drawGrid(float half_len, float res, unsigned int flag){

	float i;

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);									// Enable Blendin

	glColor4f(0.5, 0.5, 0.5, 0.5);
	for(i=0.0; i<half_len; i +=res){
		
		if(flag&XY){
		// XY
			glBegin(GL_LINES);
				glVertex3f(-half_len, i, 0.0);
				glVertex3f(half_len, i, 0.0);
			glEnd();
			glBegin(GL_LINES);
				glVertex3f(-half_len, -i, 0.0);
				glVertex3f(half_len, -i, 0.0);
			glEnd();

			glBegin(GL_LINES);
				glVertex3f(i, -half_len, 0.0);
				glVertex3f(i, half_len, 0.0);
			glEnd();
			glBegin(GL_LINES);
				glVertex3f(-i, -half_len, 0.0);
				glVertex3f(-i, half_len, 0.0);
			glEnd();
		}

		if(flag&XZ){
		// XZ
			glBegin(GL_LINES);
				glVertex3f(-half_len, 0, i);
				glVertex3f(half_len, 0, i);
			glEnd();
			glBegin(GL_LINES);
				glVertex3f(-half_len, 0, -i);
				glVertex3f(half_len, 0, -i);
			glEnd();

			glBegin(GL_LINES);
				glVertex3f(i, 0, -half_len);
				glVertex3f(i, 0, half_len);
			glEnd();
			glBegin(GL_LINES);
				glVertex3f(-i, 0, -half_len);
				glVertex3f(-i, 0, half_len);
			glEnd();
		}
	}

	glDisable(GL_BLEND);
}

int Renderer::loadGLFont()                                    // Load Bitmaps And Convert To Textures
{
        int status=FALSE;                               // Status Indicator
        AUX_RGBImageRec *TextureImage;	               // Create Storage Space For The Textures

		TextureImage =	auxDIBImageLoad("Data/textures/Font.bmp");	//?       // Load The Bitmap And Return A Pointer//loadBMP("Data/textures/Font.bmp"); //?

        if (TextureImage)
        {
                status=TRUE;                            // Set The Status To TRUE
                glGenTextures(1, &font);          // Create Two Texture

                glBindTexture(GL_TEXTURE_2D, font);
			    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
				glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);

			    if (TextureImage->data)				// If Texture Image Exists
				{
					    delete[] TextureImage->data;	// Free The Texture Image Memory
				}
				delete TextureImage;				// Free The Image Structure
        }

        return status;                                  // Return The Status
}

void Renderer::buildFont()								// Build Our Font Display List
{
	float	cx;											// Holds Our X Character Coord
	float	cy;											// Holds Our Y Character Coord
	int loop;

	base =glGenLists(256);								// Creating 256 Display Lists
	glBindTexture(GL_TEXTURE_2D, font);				// Select Our Font Texture
	for (loop=0; loop<256; loop++)						// Loop Through All 256 Lists
	{
		cx=float(loop%16)/16.0f;						// X Position Of Current Character
		cy=float(loop/16)/16.0f;						// Y Position Of Current Character

		glNewList(base+loop,GL_COMPILE);				// Start Building A List
			glBegin(GL_QUADS);							// Use A Quad For Each Character
				glTexCoord2f(cx,1-cy-0.0625f);			// Texture Coord (Bottom Left)
				glVertex2i(0,0);						// Vertex Coord (Bottom Left)
				glTexCoord2f(cx+0.0625f,1-cy-0.0625f);	// Texture Coord (Bottom Right)
				glVertex2i(16,0);						// Vertex Coord (Bottom Right)
				glTexCoord2f(cx+0.0625f,1-cy);			// Texture Coord (Top Right)
				glVertex2i(16,16);						// Vertex Coord (Top Right)
				glTexCoord2f(cx,1-cy);					// Texture Coord (Top Left)
				glVertex2i(0,16);						// Vertex Coord (Top Left)
			glEnd();									// Done Building Our Quad (Character)
			glTranslated(12,0,0);						// Move To The Right Of The Character
		glEndList();									// Done Building The Display List
	}													// Loop Until All 256 Are Built
}

void Renderer::beginOverlay(float x, float y){

	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
	glPushMatrix();										// Store The Projection Matrix
	glLoadIdentity();									// Reset The Projection Matrix
	glOrtho(0,x,0,y,-1,1);							// Set Up An Ortho Screen
	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
	glPushMatrix();										// Store The Modelview Matrix
}

void Renderer::endOverlay(){

	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
	glPopMatrix();										// Restore The Old Projection Matrix
	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
	glPopMatrix();										// Restore The Old Projection Matrix
}

void Renderer::glPrint(GLint x, GLint y, char *string, int set)	// Where The Printing Happens
{
	if (set>1)
	{
		set=1;
	}
	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);
	glBindTexture(GL_TEXTURE_2D, font);					// Select Our Font Texture

	glLoadIdentity();									// Reset The Modelview Matrix
	glTranslated(x,y,0);								// Position The Text (0,0 - Bottom Left)
	glListBase(base-32+(128*set));						// Choose The Font Set (0 or 1)
	glCallLists(strlen(string),GL_UNSIGNED_BYTE,string);// Write The Text To The Screen
}

// draw a solid disc from a bunch of triangles
//? should be display list of span
void Renderer::renderDisc(Point2* origin, float radius, Texture* texture, float LOD, float z){

	Point2 vector;
	Point2 vector1;
	float angle, i, s, c, s1, c1, fx, fy;

	if(texture){
		// calculate texture coordinates
		if(!texture->texDx || !texture->texDy){

			fx =0.5;
			fy =0.5;
		}
		else{
			fx =radius/texture->texDx;
			fy =radius/texture->texDy;
		}
		glEnable(GL_TEXTURE_2D);		
		glEnable(GL_BLEND);				
		glBindTexture(GL_TEXTURE_2D, texture->tex);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	}
	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);

	vector1 =*origin;
	s1 =(float)sin(0);
	c1 =(float)cos(0);
 
	glBegin(GL_TRIANGLES);	
	i =0;
	do	
	{	
		i+=LOD;		
		angle =i*0.01745f;	// 1/57.29577957795135 =0.01745
		s =sin(angle);
		c =cos(angle);
		vector.x =origin->x +(radius *s);
		vector.y =origin->y +(radius *c);		
		if(texture){
			glTexCoord2f(0.5, 0.5);
			glVertex3f(origin->x, origin->y, z);

			glTexCoord2f(0.5+fx*s1, 0.5+fy*c1);			
			glVertex3f(vector1.x, vector1.y, z);

			glTexCoord2f(0.5+fx*s, 0.5+fy*c);
			glVertex3f(vector.x, vector.y, z);
		}
		else{
			glVertex3f(origin->x, origin->y, z);
			glVertex3f(vector1.x, vector1.y, z);
			glVertex3f(vector.x, vector.y, z);
		}
		s1 =s;
		c1 =c;
		vector1 =vector;

	}while(i <=360);
	glEnd();

	if(texture){
		glDisable(GL_TEXTURE_2D);		
		glDisable(GL_BLEND);				
	}
}

// draw a circle from a bunch of lines
void Renderer::renderCircle(Point2* origin, float radius, float LOD){

	Point2 vector;
	Point2 vector1;
	float angle;
	float tmp =2.0f*3.14159f;

	// draw a circle from a bunch of short lines
	vector1.y =origin->y +radius;
	vector1.x =origin->x;
	glBegin(GL_LINE_STRIP);			
	for(angle =0.0f; angle <=tmp; angle +=LOD)
	{		
		vector.x=origin->x+radius*sin(angle);
		vector.y=origin->y+radius*cos(angle);		
		glVertex2d(vector1.x,vector1.y);
		vector1.y=vector.y;
		vector1.x=vector.x;			
	}
	glEnd();
}

// draw (possibly) textured rectangle at position
void Renderer::renderRect(Rect* box, Texture* texture, Point2* position, bool mirror, float z){

	assert(box);
	assert(texture);
	assert(position);

	float fx;
	float fy;
	float dx;
	float dy;

	if(texture->tex){
		// calculate texture coordinates
		dx=box->xHi -box->xLo;
		dy=box->yHi -box->yLo;
		if(!texture->texDx || !texture->texDy){

			fx =1;
			fy =1;
		}
		else{
			//? you can store 1/texture->texDx and make mutiplication instead
			fx =dx/texture->texDx;
			fy =dy/texture->texDy;
		}
		glEnable(GL_TEXTURE_2D);		
		glEnable(GL_BLEND);				
		glBindTexture(GL_TEXTURE_2D, texture->tex);

		if(!texture->texDx || !texture->texDy){
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
		}
		else{
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		}

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		glColor3ub(texture->R, texture->G, texture->B);
	}

	//? addVectToRect may be faster than pushing a matrix
	glPushMatrix();
	glTranslatef(position->x, position->y, 0);

	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);
	glBegin(GL_QUADS);
	if(texture){
		if(mirror) glTexCoord2f(0,0);
		else glTexCoord2f(fx,0);
		glVertex3f(box->xLo, box->yLo, z);
		if(mirror) glTexCoord2f(0,fy);
		else glTexCoord2f(fx,fy);
		glVertex3f(box->xLo, box->yHi, z);
		if(mirror) glTexCoord2f(fx, fy);
		else glTexCoord2f(0, fy);
		glVertex3f(box->xHi, box->yHi, z);
		if(mirror) glTexCoord2f(fx,0);
		else glTexCoord2f(0,0);
		glVertex3f(box->xHi, box->yLo, z);
	}
	else{

		glVertex3f(box->xLo, box->yLo, z);
		glVertex3f(box->xLo, box->yHi, z);
		glVertex3f(box->xHi, box->yHi, z);
		glVertex3f(box->xHi, box->yLo, z);
	}
	glEnd();
	glPopMatrix();

	if(texture){
		glDisable(GL_TEXTURE_2D);		
		glDisable(GL_BLEND);				
	}
}

// draw (posibely) textured quad
void Renderer::renderQuad(Quad<Point2*>* quad, Texture* texture, bool mirror, float z){

	if(texture){

		glEnable(GL_TEXTURE_2D);		
		glEnable(GL_BLEND);				
		glBindTexture(GL_TEXTURE_2D, texture->tex);

		// has to be the whole picture
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	}

	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);
	glBegin(GL_QUADS);
	if(texture){
		if(mirror) glTexCoord2f(0,0);
		else 
		glTexCoord2f(1,0);
		glVertex3f(quad->v[0]->x, quad->v[0]->y, z);
		if(mirror) glTexCoord2f(0,1);
		else 
		glTexCoord2f(1,1);
		glVertex3f(quad->v[1]->x, quad->v[1]->y, z);
		if(mirror) glTexCoord2f(1, 1);
		else 
		glTexCoord2f(0, 1);
		glVertex3f(quad->v[2]->x, quad->v[2]->y, z);
		if(mirror) glTexCoord2f(1,0);
		else 
		glTexCoord2f(0,0);
		glVertex3f(quad->v[3]->x, quad->v[3]->y, z);
	}
	else{

		glVertex3f(quad->v[0]->x, quad->v[0]->y, z);
		glVertex3f(quad->v[1]->x, quad->v[1]->y, z);
		glVertex3f(quad->v[2]->x, quad->v[2]->y, z);
		glVertex3f(quad->v[3]->x, quad->v[3]->y, z);
	}
	glEnd();

	if(texture){
		glDisable(GL_TEXTURE_2D);		
		glDisable(GL_BLEND);				
	}
}

// draw (possibly) textured slope (as triangle, with hipotenuse between 2 slope points)
void Renderer::renderSlope(Slope* slope, bool mirror, float z){

	assert(slope);

	float fx;
	float fy;
	float dx;
	float dy;

	if(slope->texture){
		// calculate texture coordinates
		dx=slope->pHi->x -slope->pLo->x;
		if(dx<0) dx =-dx;
		dy=slope->pHi->y -slope->pLo->y;
		if(!slope->texture->texDx || !slope->texture->texDy){

			fx =1;
			fy =1;
		}
		else{
			//? look above
			fx =dx/slope->texture->texDx;
			fy =dy/slope->texture->texDy;
		}
		glEnable(GL_TEXTURE_2D);		
		glEnable(GL_BLEND);				
		glBindTexture(GL_TEXTURE_2D, slope->texture->tex);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	}

	glPushMatrix();
	glTranslatef(slope->position->x, slope->position->y, 0);

	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);
	glBegin(GL_TRIANGLES);
	if(slope->texture){

		glTexCoord2f(fx,0);
		glVertex3f(slope->pLo->x, slope->pLo->y, z);

		glTexCoord2f(0, fy);
		glVertex3f(slope->pHi->x, slope->pHi->y, z);

		glTexCoord2f(0,0);
		glVertex3f(slope->pHi->x, slope->pLo->y, z);
	}
	else{

		glVertex3f(slope->pLo->x +slope->position->x, slope->pLo->y +slope->position->y, z);
		glVertex3f(slope->pHi->x +slope->position->x, slope->pHi->y +slope->position->y, z);
		glVertex3f(slope->pHi->x +slope->position->x, slope->pLo->y +slope->position->y, z);
	}
	glEnd();
	glPopMatrix();

	if(slope->texture){
		glDisable(GL_TEXTURE_2D);		
		glDisable(GL_BLEND);				
	}
}

// draw rectangle at position
void Renderer::renderRect(Rect* rect, Point2* position, unsigned int mode){

	glPushMatrix();
	glTranslatef(position->x, position->y, 0);

	glPolygonMode(GL_FRONT_AND_BACK,  mode);
	glBegin(GL_QUADS);
		glVertex2f(rect->xHi, rect->yHi);
		glVertex2f(rect->xHi, rect->yLo);
		glVertex2f(rect->xLo, rect->yLo);
		glVertex2f(rect->xLo, rect->yHi);
	glEnd();
	glPopMatrix();
}

// draw cross
void Renderer::drawCross(float dx, float dy, float x, float y){	//D

	glColor4ub(255, 255, 255, 127);
	glBegin(GL_LINES);
		glVertex2f(x, y-dy*0.5);
		glVertex2f(x, y+dy*0.5);
		glVertex2f(x-dx*0.5, y);
		glVertex2f(x+dx*0.5, y);
	glEnd();
}

// draw level at layer
void Renderer::renderLevel(Level* level, int layer, Camera* cam){

	int i;
	list<Platform*>::iterator iter_platform;
//	list<Platform*>::iterator iter_f;
	list<Zomby*>::iterator iter_z;
	list<Slope*>::iterator iter_sl;
	list<Circle*>::iterator iter_circle;
	list<Fx*>::iterator iter_fx;
	list<Projectile*>::iterator iter_projectile;
	list<Kolobok*>::iterator iter_kolobok;
	list<Polygon2*>::iterator iter_polygon;
	list<Bird*>::iterator iter_bird;
	Physics* ph =Physics::Instance();
	Platform* platform;
	Bird* bird;
	Zomby* zomby;
	Kolobok* kolobok;
	Slope* slope;
	Circle* circle;
	Fx* fx;
	Projectile* projectile;
	Polygon2* polygon;
	int num;

	Rect* rect;
	Texture* sprite;
	Point2* position;
	bool mirror;

	if(!level) return;

	// render platforms
	num =level->platforms_num;
	for(i =0; i <num; i++)
	{
		platform =level->platforms[i];
		if(platform->layer!=layer) continue;

		rect =platform->frame->box;
		sprite =platform->texture;
		position =platform->position;

		renderRect(rect, sprite, position, false, platform->layer);
	}

	// render floors
	Rect rectT;
	num =level->floors_num;
	for(i =0; i <num; i++)
	{
		platform =level->floors[i];
		if(platform->layer!=layer) continue;

		rect =platform->frame->box;
		sprite =platform->texture;
		position =platform->position;

		#ifdef _OPTIMIZE_renderLevel
		rectT =*rect;
		addVectToRect(&rectT, position);
		if(!ph->collide_Rect_Rect_S(&rectT, cam->rect)) continue;
		#endif

		renderRect(rect, sprite, position, false, platform->layer);
	}

	// render zombies
	for(iter_z = level->zombies.begin(); iter_z != level->zombies.end(); iter_z++)
	{
		zomby =*iter_z;
		if(!zomby->active) continue;		
		if(zomby->layer!=layer) continue;

		rect =zomby->cur_animation->frames[zomby->cur_animation->cur_frame]->box;
		sprite =zomby->cur_animation->sprites[zomby->cur_animation->cur_frame];

//?
//		float rel =(float)((*iter_z)->ai->max_time -(*iter_z)->ai->cur_time)/(float)(*iter_z)->ai->max_time;//? var
//		if(rel<0)
//			rel =0;
//		sprite->R =255*rel;
//		sprite->B =255*rel;
		position =zomby->position;

		mirror =zomby->orientation->x>0;
		mirror =mirror^zomby->mirrored;

		renderRect(rect, sprite, position, mirror, zomby->layer);
		renderExtraAnimation(zomby);
	}

	// render birds
	for(iter_bird = level->birds.begin(); iter_bird != level->birds.end(); iter_bird++)
	{
		bird =*iter_bird;
		if(!bird->active) continue;		
		if(bird->layer!=layer) continue;

		rect =bird->cur_animation->frames[bird->cur_animation->cur_frame]->box;
		sprite =bird->cur_animation->sprites[bird->cur_animation->cur_frame];
		position =bird->position;
		mirror =bird->orientation->x>0;
		mirror =mirror^bird->mirrored;

		renderRect(rect, sprite, position, mirror, bird->layer);
	}

	// render koloboks
	for(iter_kolobok = level->koloboks.begin(); iter_kolobok != level->koloboks.end(); iter_kolobok++)
	{
		kolobok =*iter_kolobok;
		if(kolobok->layer!=layer) continue;

		renderDisc(kolobok->position, kolobok->circle->radius, kolobok->circle->texture, kolobok->circle->LOD, kolobok->layer);
	}

	// render slopes
	for(iter_sl = level->slopes.begin(); iter_sl != level->slopes.end(); iter_sl++)
	{
		slope =*iter_sl;
		if(slope->layer!=layer) continue;

		renderSlope(slope, false, slope->layer);
	}

	// render items
	for(iter_platform = level->items.begin(); iter_platform != level->items.end(); iter_platform++)
	{
		platform =*iter_platform;
		if(platform->layer!=layer) continue;

		rect =platform->frame->box;
		sprite =platform->texture;
		position =platform->position;

		renderRect(rect, sprite, position, false, platform->layer);
	}

	// render images
	for(iter_platform = level->images.begin(); iter_platform != level->images.end(); iter_platform++)
	{
		platform =*iter_platform;
		if(platform->layer!=layer) continue;

		rect =platform->frame->box;
		sprite =platform->texture;
		position =platform->position;

		renderRect(rect, sprite, position, false, platform->layer);
	}

	// render circles
	for(iter_circle = level->circles.begin(); iter_circle != level->circles.end(); iter_circle++)
	{
		circle =*iter_circle;
		if(circle->layer!=layer) continue;

		renderDisc(circle->position, circle->radius, circle->texture, circle->LOD, circle->layer);
	}

	// render effects
	for(iter_fx = level->effects.begin(); iter_fx != level->effects.end(); iter_fx++)
	{
		fx =*iter_fx;
		if(fx->layer!=layer) continue;

		sprite =fx->animation->sprites[fx->animation->cur_frame];

		if(fx->type==FX_DIRECTED)
			renderQuad(fx->quad, sprite, true, fx->layer);
		else if(fx->type==FX_CENTERED){
			rect =fx->animation->frames[fx->animation->cur_frame]->body;
			sprite =fx->animation->sprites[fx->animation->cur_frame];
			renderRect(rect, sprite, fx->position, false, fx->layer);
		}
	}

	// render polygons
	for(iter_polygon = level->polygons.begin(); iter_polygon != level->polygons.end(); iter_polygon++)
	{
		polygon =*iter_polygon;
		if(polygon->layer!=layer) continue;

		renderPolygon(polygon, polygon->position, polygon->layer);
	}

	// render projectiles
	for(iter_projectile = level->projectiles.begin(); iter_projectile != level->projectiles.end(); iter_projectile++)
	{
		//? layer?
		projectile =*iter_projectile;

		glBegin(GL_POINTS);
			glColor3ub(255, 255, 255);
			glVertex3f(projectile->position->x, projectile->position->y, projectile->layer);
		glEnd();
	}
}

void Renderer::renderAll(Level* level, Character* player, Camera* c){

	int i;
	Game* game =Game::Instance();
	list<Cloud*>::iterator iter_cloud;
	Rect* rect =player->cur_animation->frames[player->cur_animation->cur_frame]->box;
	Texture* sprite =player->cur_animation->sprites[player->cur_animation->cur_frame];

//	glEnable(GL_DEPTH_TEST);
	// render background
	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);
	glBegin(GL_QUADS);
		glColor3ub(level->r_xHi_yHi, level->g_xHi_yHi, level->b_xHi_yHi);
		glVertex3f(level->sky->xHi, level->sky->yHi, 1000);	//? 1000 constant
		glColor3ub(level->r_xHi_yLo, level->g_xHi_yLo, level->b_xHi_yLo);
		glVertex3f(level->sky->xHi, level->sky->yLo, 1000);
		glColor3ub(level->r_xLo_yLo, level->g_xLo_yLo, level->b_xLo_yLo);
		glVertex3f(level->sky->xLo, level->sky->yLo, 1000);
		glColor3ub(level->r_xLo_yHi, level->g_xLo_yHi, level->b_xLo_yHi);
		glVertex3f(level->sky->xLo, level->sky->yHi, 1000);
	glEnd();

	for(iter_cloud = level->clouds.begin(); iter_cloud != level->clouds.end(); iter_cloud++)
	{
		renderRect((*iter_cloud)->rect, (*iter_cloud)->texture, (*iter_cloud)->position, false, (*iter_cloud)->z);
	}

//	for(i=level->layers-1; i>=0; i--){
	for(i=0; i<level->layers; i++){

		renderLevel(level, i, c);
		if(player->layer==i){
			renderRect(rect, sprite, player->position, (player->orientation->x>0)^player->mirrored, player->layer);
			renderExtraAnimation(player);
		}
	}
//	glDisable(GL_DEPTH_TEST);	//?

	drawHUD(((Hunter*)player)->ammo, game->scores);	//? what if it is not a hunter
}
// ----------------------------- FOR DEBUG --------------------------
void Renderer::renderPlayerAux(Character* player){

	Frame* frame =player->cur_animation->frames[player->cur_animation->cur_frame];

	glColor3ub(255, 255, 0);
	renderRect(frame->box, player->position, GL_LINE);

	glColor3ub(255, 255, 255);
	renderRect(frame->body, player->position, GL_LINE);
/*
	glColor3ub(0, 255, 0);
	glBegin(GL_LINES);

        glVertex3f(frame->body->xLo +player->position->x, frame->body->yLo +player->position->y, 10.0);
		glVertex3f(frame->body->xLo +player->position->x +player->velocity->x*10, frame->body->yLo +player->position->y +player->velocity->y*10, 10.0);
	glEnd();
*/
}

void Renderer::renderLevelAux(Level* level){	//D

	int i;
	Point2** attack;
	float x,y;
	int frame_num;
	list<Platform*>::iterator iter_platform;
	list<Zomby*>::iterator iter_zomby;
	list<Fx*>::iterator iter_fx;
	list<Slope*>::iterator iter_sl;
	list<Circle*>::iterator iter_circle;
	list<Platform*>::iterator iter_item;
	list<Kolobok*>::iterator iter_kolobok;
	list<Source*>::iterator iter_source;
	list<Bird*>::iterator iter_bird;

	// graphics -----------------------------------------------------
	glColor3ub(255, 255, 0);

	for(i =0; i <level->platforms_num; i++)
		renderRect(level->platforms[i]->frame->box, level->platforms[i]->position, GL_LINE);

	for(i =0; i <level->floors_num; i++)
		renderRect(level->floors[i]->frame->box, level->floors[i]->position, GL_LINE);

	for(iter_zomby = level->zombies.begin(); iter_zomby != level->zombies.end(); iter_zomby++){
		if(!(*iter_zomby)->active) continue;
		renderRect((*iter_zomby)->cur_animation->frames[(*iter_zomby)->cur_animation->cur_frame]->box, (*iter_zomby)->position, GL_LINE);
	}

	for(iter_bird = level->birds.begin(); iter_bird != level->birds.end(); iter_bird++){
		if(!(*iter_bird)->active) continue;
		renderRect((*iter_bird)->cur_animation->frames[(*iter_bird)->cur_animation->cur_frame]->box, (*iter_bird)->position, GL_LINE);
	}

	for(iter_fx = level->effects.begin(); iter_fx != level->effects.end(); iter_fx++)
	{
		if((*iter_fx)->type==FX_DIRECTED){
			glPolygonMode(GL_FRONT_AND_BACK,  GL_LINE);		
			glBegin(GL_QUADS);
				glVertex2f((*iter_fx)->quad->v[0]->x, (*iter_fx)->quad->v[0]->y);
				glVertex2f((*iter_fx)->quad->v[1]->x, (*iter_fx)->quad->v[1]->y);
				glVertex2f((*iter_fx)->quad->v[2]->x, (*iter_fx)->quad->v[2]->y);
				glVertex2f((*iter_fx)->quad->v[3]->x, (*iter_fx)->quad->v[3]->y);
			glEnd();
		}
		else if((*iter_fx)->type==FX_CENTERED){

			renderRect((*iter_fx)->animation->frames[(*iter_fx)->animation->cur_frame]->box, (*iter_fx)->position, GL_LINE);
		}
	}

	for(iter_sl = level->slopes.begin(); iter_sl != level->slopes.end(); iter_sl++)
	{
		glBegin(GL_LINES);
			glVertex2f((*iter_sl)->pLo->x +(*iter_sl)->position->x, (*iter_sl)->pLo->y +(*iter_sl)->position->y);
			glVertex2f((*iter_sl)->pHi->x +(*iter_sl)->position->x, (*iter_sl)->pHi->y +(*iter_sl)->position->y);
		glEnd();
	}

	for(iter_circle = level->circles.begin(); iter_circle != level->circles.end(); iter_circle++)
		renderCircle( (*iter_circle)->position, (*iter_circle)->radius, 0.1f);	//?

	for(iter_kolobok = level->koloboks.begin(); iter_kolobok != level->koloboks.end(); iter_kolobok++)
		renderCircle( (*iter_kolobok)->position, (*iter_kolobok)->circle->radius, 0.1f);	//?0.1f

	for(iter_item = level->items.begin(); iter_item != level->items.end(); iter_item++)
		renderRect((*iter_item)->frame->box, (*iter_item)->position, GL_LINE);

	renderRect(level->finish->frame->box, level->finish->position, GL_LINE);

	// physics ------------------------------------------
	glColor3ub(255, 255, 255);

	for(i =0; i <level->platforms_num; i++)
		renderRect(level->platforms[i]->frame->body, level->platforms[i]->position, GL_LINE);

	for(i =0; i <level->floors_num; i++)
	{
		glBegin(GL_LINES);
			glVertex2f(level->floors[i]->frame->body->xLo +level->floors[i]->position->x, level->floors[i]->frame->body->yHi +level->floors[i]->position->y);
			glVertex2f(level->floors[i]->frame->body->xHi +level->floors[i]->position->x, level->floors[i]->frame->body->yHi +level->floors[i]->position->y);
		glEnd();
	}

	for(iter_zomby = level->zombies.begin(); iter_zomby != level->zombies.end(); iter_zomby++){
		if(!(*iter_zomby)->active) continue;
		renderRect((*iter_zomby)->cur_animation->frames[(*iter_zomby)->cur_animation->cur_frame]->body, (*iter_zomby)->position, GL_LINE);
	}

	for(iter_bird = level->birds.begin(); iter_bird != level->birds.end(); iter_bird++){
		if(!(*iter_bird)->active) continue;
		renderRect((*iter_bird)->cur_animation->frames[(*iter_bird)->cur_animation->cur_frame]->body, (*iter_bird)->position, GL_LINE);
	}

	for(iter_sl = level->slopes.begin(); iter_sl != level->slopes.end(); iter_sl++)
	{
		glBegin(GL_LINES);
			glVertex2f((*iter_sl)->pLo_ph->x +(*iter_sl)->position->x, (*iter_sl)->pLo_ph->y +(*iter_sl)->position->y);
			glVertex2f((*iter_sl)->pHi_ph->x +(*iter_sl)->position->x, (*iter_sl)->pHi_ph->y +(*iter_sl)->position->y);
		glEnd();
	}

	for(iter_circle = level->circles.begin(); iter_circle != level->circles.end(); iter_circle++)
		renderCircle( (*iter_circle)->position, (*iter_circle)->radius_ph, 0.1f);	//?

	for(iter_kolobok = level->koloboks.begin(); iter_kolobok != level->koloboks.end(); iter_kolobok++)
		renderCircle( (*iter_kolobok)->position, (*iter_kolobok)->circle->radius_ph, 0.1f);	//?0.1f

	for(iter_item = level->items.begin(); iter_item != level->items.end(); iter_item++)
		renderRect((*iter_item)->frame->body, (*iter_item)->position, GL_LINE);

	for(i =0; i<level->respawns_num; i++)
		drawCross(20, 20, level->respawns[i]->position->x, level->respawns[i]->position->y);

	renderRect(level->finish->frame->body, level->finish->position, GL_LINE);

	glColor3ub(64, 64, 255);
	for(iter_source = level->sources.begin(); iter_source != level->sources.end(); iter_source++){

		V_TMP.x =(*iter_source)->x;
		V_TMP.y =(*iter_source)->y;
		renderCircle( &V_TMP, (*iter_source)->gain*5 , 0.3f);	//?0.1f
	}

	// punches
	for(iter_zomby = level->zombies.begin(); iter_zomby != level->zombies.end(); iter_zomby++){
		if(!(*iter_zomby)->active) continue;
		if((*iter_zomby)->state==STATE_ATTACK){

			frame_num =(*iter_zomby)->cur_animation->cur_frame;
			if((*iter_zomby)->cur_animation==(*iter_zomby)->ani_bite)
				attack =(*iter_zomby)->bite;
			else if((*iter_zomby)->cur_animation==(*iter_zomby)->ani_kick)
				attack =(*iter_zomby)->kick;

			if(attack[frame_num]){

				(*iter_zomby)->getCenter(&V_TMP);
				if((*iter_zomby)->orientation->x>0)
					x =V_TMP.x +attack[frame_num]->x;
				else
					x =V_TMP.x -attack[frame_num]->x;
				y =attack[frame_num]->y +(*iter_zomby)->position->y;

				glBegin(GL_POINTS);
					glColor3ub(255, 0, 0);
					glVertex2f(x, y);
				glEnd();
			}
		}
	}

	// deadline ----------------------------------------------
	glColor3ub(255, 0, 0);
	glBegin(GL_LINES);
		glVertex2f(level->rect->xLo, level->deadline);
		glVertex2f(level->rect->xHi, level->deadline);		
	glEnd();

	glColor3ub(255, 127, 0);
	renderRect(level->rect, &V_NULL, GL_LINE);
}

void Renderer::drawStartButton(){

	glColor3ub(127, 127, 0);
	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);

	glPushMatrix();
	glTranslatef(320, 10, 0);
	renderRect(&R_BUTTON, start_game, &V_NULL, false);
	glPopMatrix();
}

void Renderer::drawExitButton(){

	glColor3ub(127, 127, 127);
	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);

	glPushMatrix();
	glTranslatef(320, 260, 0);
	renderRect(&R_BUTTON, exit_game, &V_NULL, false);
	glPopMatrix();
}

void Renderer::drawMenu(){

	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
	glLoadIdentity();									// Reset The Projection Matrix

	glOrtho(800, 0, 0, 600, -1, 1);

	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
	glLoadIdentity();									// Reset The Modelview Matrix	

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer

	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);
	glColor3ub(0, 127, 0);
	renderRect(&R_MENU, main_menu, &V_NULL, false);

	drawStartButton();
	drawExitButton();
}

void Renderer::setCamera(Camera* c){

	if(!c) return;

	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
	glLoadIdentity();									// Reset The Projection Matrix

	// Calculate The Aspect Ratio Of The Window
	c->eye->x =c->rect->xLo +(c->rect->xHi -c->rect->xLo)/2;
	c->eye->y =c->rect->yLo +(c->rect->yHi -c->rect->yLo)/2;
//	glOrtho(c->rect->xHi, c->rect->xLo, c->rect->yLo, c->rect->yHi, c->frustum_near, c->frustum_far);
//	glFrustum(-c->width/2, c->width/2, -c->height/2, c->height/2, c->frustum_near, c->frustum_far);
	gluPerspective(60, 1.33, 0.1, c->frustum_far);
	gluLookAt(c->eye->x, c->eye->y, c->frustum_near, c->eye->x, c->eye->y, 0, 0, 1, 0);

	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
	glLoadIdentity();									// Reset The Modelview Matrix	
}

void Renderer::killFont()											// Delete The Font From Memory
{
	glDeleteLists(base,256);							// Delete All 256 Display Lists
	glDeleteTextures(1, &font);
}

// Resize And Initialize The GL Window
void Renderer::reSizeGLScene(GLsizei width, GLsizei height)
{
	assert(width);
	assert(height);

	if (height==0)										// Prevent A Divide By Zero By
	{
		height=1;										// Making Height Equal One
	}

	glViewport(0,0,width,height);						// Reset The Current Viewport
}

int Renderer::initGL()										// All Setup For OpenGL Goes Here
{
	if (!loadGLFont())								// Jump To Texture Loading Routine
	{
		return FALSE;									// If Texture Didn't Load Return FALSE
	}
	buildFont();	

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);				// Clear The Background Color To Black
	glDisable(GL_DEPTH_TEST);	//?
//	glEnable(GL_CULL_FACE);
	glFrontFace(GL_CCW);
	glCullFace(GL_FRONT);

	tobj = gluNewTess();
	gluTessCallback(tobj, GLU_BEGIN, (void (__stdcall*)()) glBegin);
	gluTessCallback(tobj, GLU_VERTEX,(void (__stdcall*)()) glVertex2fv);  /* semi-tricky */
	gluTessCallback(tobj, GLU_END, (void (__stdcall*)())glEnd);

	return TRUE;										// Initialization Went OK
}

void Renderer::releaseGL(){

	killFont();
//	if(tobj){
	gluDeleteTess(tobj);
	tobj =NULL;
}

int Renderer::renderGLScene(Level* level, Character* player, Camera* camera, unsigned int extra)									// Here's Where We Do All The Drawing
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer

	renderAll(level, player, camera);

	if(extra&DRAW_GRID)
		drawGrid(10000, 100, XY);

	if(extra&DRAW_GEOMETRY){
		renderPlayerAux(player);
		renderLevelAux(level);
	}

	if(extra&DRAW_CAMERA){
		glColor3ub(0, 255, 0);
		renderRect(camera->rect, &V_NULL, GL_LINE);
	}

	if(extra&DRAW_AXIS)
		drawAxis(10000);

	return TRUE;										// Everything Went OK
}

void Renderer::drawInfo(Character* player){

	char buffer[16] ={0};

	glLoadIdentity();									// Reset The Modelview Matrix
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glEnable(GL_BLEND);									// Enable Blendin

	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);
	glColor4ub(0, 64, 255, 127);
	glBegin(GL_QUADS);
		glVertex2f(0, 370);
		glVertex2f(0, 480);
		glVertex2f(150, 480);
		glVertex2f(150, 370);
	glEnd();

	glBlendFunc(GL_SRC_ALPHA,GL_ONE);					// Select The Type Of Blending
	glEnable(GL_TEXTURE_2D);									// Enable Blendin
	glColor3f(1.0, 1.0, 0.0);

	int playerStateX = 10;
	int playerStateY = 460;

	switch(player->state){
	case STATE_MOVE:
		glPrint(playerStateX,playerStateY,"MOVE",0);
		break;
	case STATE_STILL:
		glPrint(playerStateX,playerStateY,"STILL",0);
		break;
	case STATE_JUMP:
		glPrint(playerStateX,playerStateY,"JUMP",0);
		break;
	case STATE_ATTACK:
		glPrint(playerStateX,playerStateY,"ATTACK",0);
		break;
	case STATE_FALL:
		glPrint(playerStateX,playerStateY,"FALL",0);
		break;
	case STATE_DEAD:
		glPrint(playerStateX,playerStateY,"DEAD",0);
		break;
	case STATE_RELOAD:
		glPrint(playerStateX,playerStateY,"RELOAD",0);
		break;
	}

	sprintf(buffer, "vx: %d", static_cast<int>(player->velocity->x));
	glPrint(10,440,buffer,0);

	sprintf(buffer, "vy: %d", static_cast<int>(player->velocity->y));
	glPrint(10,420,buffer,0);

	sprintf(buffer, "x:  %d", static_cast<int>(player->position->x));
	glPrint(10,400,buffer,0);

	sprintf(buffer, "y:  %d", static_cast<int>(player->position->y));
	glPrint(10,380,buffer,0);

	glDisable(GL_BLEND);									// Enable Blendin
	glDisable(GL_TEXTURE_2D);									// Enable Blendin
}

void Renderer::drawPause(){

	glBlendFunc(GL_SRC_ALPHA,GL_ONE);					// Select The Type Of Blending
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);

	glLoadIdentity();									// Reset The View
	glColor3f(1.0, 1.0, 0.0);
	glPrint(320,240,"PAUSE",0);							// Print GL Text To The Screen  at (640/2, 480/2)

	glDisable(GL_BLEND);
	glDisable(GL_TEXTURE_2D);
}

void Renderer::drawWon(){

	glBlendFunc(GL_SRC_ALPHA,GL_ONE);					// Select The Type Of Blending
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glEnable(GL_TEXTURE_2D);									// Enable Blendin
	glEnable(GL_BLEND);									// Enable Blendin

	glLoadIdentity();									// Reset The View
	glColor3f(1.0, 1.0, 0.0);
	glPrint(640/2-50,480/2+50,"YOU HAVE WON!!!",0);		// Print GL Text To The Screen
	glPrint(640/2-55,480/2+30,"PLAY AGAIN? (Y/N)",0);	// Print GL Text To The Screen

	glDisable(GL_BLEND);									// Enable Blendin
	glDisable(GL_TEXTURE_2D);									// Enable Blendin
}

void Renderer::drawLost(){

	glBlendFunc(GL_SRC_ALPHA,GL_ONE);					// Select The Type Of Blending
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glEnable(GL_TEXTURE_2D);									// Enable Blendin
	glEnable(GL_BLEND);									// Enable Blendin

	glLoadIdentity();									// Reset The View
	glColor3f(1.0, 1.0, 0.0);
	glPrint(640/2-55,480/2+50,"YOU HAVE LOST :-(",0);		// Print GL Text To The Screen
	glPrint(640/2-55,480/2+30,"PLAY AGAIN? (Y/N)",0);		// Print GL Text To The Screen

	glDisable(GL_BLEND);									// Enable Blendin
	glDisable(GL_TEXTURE_2D);									// Enable Blendin
}

void Renderer::drawPerformance(int fps, int lms, int speed, int cycle_time){
	
	char buffer[16] ={0};

	glLoadIdentity();									// Reset The Modelview Matrix
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glEnable(GL_BLEND);									// Enable Blendin

	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);
	glColor4ub(0, 64, 255, 127);
	glBegin(GL_QUADS);
		glVertex2f(470, 370);
		glVertex2f(470, 480);
		glVertex2f(640, 480);
		glVertex2f(640, 370);
	glEnd();

	glBlendFunc(GL_SRC_ALPHA,GL_ONE);					// Select The Type Of Blending
	glEnable(GL_TEXTURE_2D);									// Enable Blendin
	glColor3f(1.0, 1.0, 0.0);

	sprintf(buffer, "FPS: %d", fps);
	glPrint(500,460,buffer,0);
	sprintf(buffer, "Lms: %d", lms);
	glPrint(500,440,buffer,0);
	sprintf(buffer, "speed: %d%%", speed);
	glPrint(500,420,buffer,0);
	sprintf(buffer, "dt: %d", (int)LOGIC_CYCLE_TIME);
	glPrint(500,400,buffer,0);
	if(cycle_time<1)
		sprintf(buffer, "ccl: --", cycle_time);
	else
		sprintf(buffer, "ccl: %d", cycle_time);
	glPrint(500,380,buffer,0);

	sprintf(buffer, "mint: %f", TTT);
	glPrint(400,360,buffer,0);

	glDisable(GL_BLEND);									// Enable Blendin
	glDisable(GL_TEXTURE_2D);									// Enable Blendin
}

void Renderer::drawLevelInfo(Level* level){
	
	char buffer[160] ={0};

	glLoadIdentity();									// Reset The Modelview Matrix
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glEnable(GL_BLEND);

	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);
	glColor4ub(255, 64, 0, 127);
	glBegin(GL_QUADS);
		glVertex2f(470, 270);
		glVertex2f(470, 360);
		glVertex2f(640, 360);
		glVertex2f(640, 270);
	glEnd();

	glBlendFunc(GL_SRC_ALPHA,GL_ONE);					// Select The Type Of Blending
	glEnable(GL_TEXTURE_2D);
	glColor3f(1.0, 1.0, 0.0);

	sprintf(buffer, "plfs: %d", level->platforms_num);
	glPrint(500,340,buffer,0);		// Print GL Text To The Screen
	sprintf(buffer, "floors: %d", level->floors_num);
	glPrint(500,320,buffer,0);		// Print GL Text To The Screen
	sprintf(buffer, "slopes: %d", level->slopes.size());
	glPrint(500,300,buffer,0);		// Print GL Text To The Screen
	sprintf(buffer, "circles: %d", level->circles.size());
	glPrint(500,280,buffer,0);		// Print GL Text To The Screen

	glDisable(GL_BLEND);									// Enable Blendin
	glDisable(GL_TEXTURE_2D);									// Enable Blendin
}

void Renderer::renderPolygon(Polygon2* polygon, Point2* position, float z){

	assert(polygon);
	assert(position);

	int i;
	float fx, fy, dx, dy, tx, ty;

	if(polygon->texture){
		// calculate texture coordinates
		dx =polygon->box->xHi -polygon->box->xLo;
		dy =polygon->box->yHi -polygon->box->yLo;
		if(!polygon->texture->texDx || !polygon->texture->texDy){

			fx =1;
			fy =1;
		}
		else{
			//? look above
			fx =dx/polygon->texture->texDx;
			fy =dy/polygon->texture->texDy;
		}
		glEnable(GL_TEXTURE_2D);		
		glEnable(GL_BLEND);				
		glBindTexture(GL_TEXTURE_2D, polygon->texture->tex);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		glColor3ub(polygon->texture->R, polygon->texture->G, polygon->texture->B);
	}

	glPolygonMode(GL_FRONT_AND_BACK,  GL_FILL);
	glBegin(GL_POLYGON);

	if(polygon->texture){

		for(i=0; i<polygon->nElem; i++){
			
			tx =((polygon->box->xHi -polygon->pList[i]->x)/dx) *fx;
			ty =((polygon->box->yHi -polygon->pList[i]->y)/dy) *fy;
			glTexCoord2f(tx,ty);

			glVertex3f(polygon->pList[i]->x +position->x, polygon->pList[i]->y +position->y, z);
		}
	}
	else{
		glColor3ub(0,0,0);
		for(i=0; i<polygon->nElem; i++){
			glVertex3f(polygon->pList[i]->x +position->x, polygon->pList[i]->y +position->y, z);
		}
	}
	glEnd();

	if(polygon->texture){
		glDisable(GL_TEXTURE_2D);		
		glDisable(GL_BLEND);				
	}
}

void Renderer::drawHUD(int ammo, int score){

	beginOverlay(640, 480);
	char buffer[16] ={0};

	glLoadIdentity();									// Reset The Modelview Matrix
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glEnable(GL_BLEND);									// Enable Blendin

	glBlendFunc(GL_SRC_ALPHA,GL_ONE);					// Select The Type Of Blending
	glEnable(GL_TEXTURE_2D);									// Enable Blendin
	glColor3f(1.0, 0.0, 0.0);

	sprintf(buffer, "SCORE: %d", score);
	glPrint(500,460,buffer,0);		// Print GL Text To The Screen
	sprintf(buffer, "AMMO: %d", ammo);
	glPrint(10,460,buffer,0);		// Print GL Text To The Screen

	glDisable(GL_BLEND);									// Enable Blendin
	glDisable(GL_TEXTURE_2D);									// Enable Blendin

	endOverlay();
}
